package org.jeecg.modules.system.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.common.util.encryption.AesEncryptUtil;
import org.jeecg.common.util.encryption.EncryptedString;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.constant.UserTypeEnum;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.CustomerSysLoginModel;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.service.ISysLogService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.util.RandImageUtil;
import org.jeecg.modules.third.amap.service.AmapService;
import org.jeecg.modules.third.sendsms.service.SendSmsService;
import org.jeecg.modules.wlhy.company.entity.HyCompany;
import org.jeecg.modules.wlhy.company.service.IHyCompanyService;
import org.jeecg.modules.wlhy.customer.entity.HyCustomer;
import org.jeecg.modules.wlhy.customer.entity.HyCustomerCompany;
import org.jeecg.modules.wlhy.customer.entity.HyCustomerUser;
import org.jeecg.modules.wlhy.customer.service.IHyCustomerCompanyService;
import org.jeecg.modules.wlhy.customer.service.IHyCustomerService;
import org.jeecg.modules.wlhy.customer.service.IHyCustomerUserService;
import org.jeecg.modules.wlhy.hyproject.entity.HyProject;
import org.jeecg.modules.wlhy.hyproject.service.IHyProjectService;
import org.jeecg.modules.wlhy.setting.service.IHySettingService;
import org.jeecg.modules.wlhy.utils.UserUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;
import zyb.cn.hutool.crypto.SmUtil;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @Author scott
 * @since 2018-12-17
 */
@RestController
@RequestMapping("/sys")
@Api(tags = "用户登录")
@Slf4j
public class LoginController {

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ISysBaseAPI sysBaseAPI;

    @Autowired
    private ISysLogService logService;

    @Lazy
    @Resource
    private RedisUtil redisUtil;

    @Autowired
    private ISysDepartService sysDepartService;

    @Autowired
    private ISysDepartService departService;

    @Resource
    private BaseCommonService baseCommonService;

    @Autowired
    private SendSmsService sendSmsService;

    @Autowired
    private IHyCustomerCompanyService hyCustomerCompanyService;

    @Autowired
    private IHyCompanyService hyCompanyService;

    @Autowired
    private IHyCustomerService hyCustomerService;

    @Autowired
    private IHyCustomerUserService hyCustomerUserService;

    @Autowired
    private UserUtil userUtil;

    @Autowired
    private IHySettingService settingService;

    @Autowired
    private IHyProjectService hyProjectService;

    @Autowired
    private AmapService amapService;

    @Value(value="${params.id:dev}")
    private String paramsId;

    @Value(value="${customer.roleid}")
    private String customerRoleID;

    @Value(value="${customer.departpid}")
    private String customerDepartpid;

    @Value(value="${jeecg.shiro.requestallow:}")
    private String requestAllow;

    @Value(value="${jeecg.shiro.requestAllowLongDays:}")
    private String requestAllowLongDays;

    @Value(value="${jeecg.shiro.customerSign:}")
    private String customerSign;

    private final static Integer LOGIN_TYPE_PASSWORD = 1;

    private final static Integer LOGIN_TYPE_SMS = 2;

    private final static Integer LOGIN_BAN_TIME_MAX = 10;

    private final static Integer LOGIN_IP_BAN_TIME_MAX = 30;

    private final static Integer LOGIN_SMS_BAN_TIME_MAX = 100;

    private final static Integer LOGIN_SMS_MOBILE_BAN_TIME_MAX = 40;

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";

    //设置登陆次数超过5次，锁定30分钟
    private boolean isDisableLogin(String username) {
        String loginkey = "loginfail:" + username;
        String loginBankey = "loginban:" + username;
        //检查是否超过5次
        if (redisUtil.hasKey(loginkey)) {
            int loginNum = (int) redisUtil.get(loginkey);
            if (loginNum >= 5) {
                //再次请求超过次数，永久锁定
                int loginBanNum = (int) redisUtil.get(loginBankey);
                loginBanNum = loginBanNum + 1;
                if (loginBanNum >= LOGIN_BAN_TIME_MAX.intValue()) {
                    redisUtil.set(loginBankey, loginBanNum, -1);
                } else {
                    redisUtil.set(loginBankey, loginBanNum, 30 * 24 * 60 * 60);
                }
                return true;
            }
        }
        return false;
    }

    //设置登陆总计失败次数超过20次，永久锁定
    private boolean isBannedLogin(String username) {
        String loginBankey = "loginban:" + username;
        //检查是否超过20次
        if (redisUtil.hasKey(loginBankey)) {
            int loginNum = (int) redisUtil.get(loginBankey);
            if (loginNum >= LOGIN_BAN_TIME_MAX.intValue()) {
                return true;
            }
        }
        return false;
    }

    //设置登陆次数超过5次，锁定30分钟
    //设置Ban登录策略，30天内有连续错误登录信息BAN用户
    private void addLoginNum(String username) {
        String loginkey = "loginfail:" + username;
        String loginBankey = "loginban:" + username;
        if (!redisUtil.hasKey(loginkey)) {
            redisUtil.set(loginkey, 1, 30 * 60);
        } else {
            int loginNum = (int) redisUtil.get(loginkey);
            loginNum = loginNum + 1;
            redisUtil.set(loginkey, loginNum, 30 * 60);
        }

        if (!redisUtil.hasKey(loginBankey)) {
            redisUtil.set(loginBankey, 1, 30 * 24 * 60 * 60);
        } else {
            int loginBanNum = (int) redisUtil.get(loginBankey);
            loginBanNum = loginBanNum + 1;
            if (loginBanNum >= LOGIN_BAN_TIME_MAX.intValue()) {
                redisUtil.set(loginBankey, loginBanNum, -1);
            } else {
                redisUtil.set(loginBankey, loginBanNum, 30 * 24 * 60 * 60);
            }
        }
    }

    //设置IP登陆次数超过次数，临时永久锁定
    private boolean isBannedIP() {
        String ipAddrLogin = "loginipfail:" + IPUtils.getIpAddr();
        //检查是否超过次数
        if (redisUtil.hasKey(ipAddrLogin)) {
            int loginIPNum = (int) redisUtil.get(ipAddrLogin);
            if (loginIPNum >= LOGIN_IP_BAN_TIME_MAX.intValue()) {
                return true;
            }
        }
        return false;
    }

    //设置7天内登陆失败IP
    private void addLoginIP() {
        String ipAddrLogin = "loginipfail:" + IPUtils.getIpAddr();
        if (!redisUtil.hasKey(ipAddrLogin)) {
            redisUtil.set(ipAddrLogin, 1, 7 * 24 * 60 * 60);
        } else {
            int loginIPNum = (int) redisUtil.get(ipAddrLogin);
            loginIPNum = loginIPNum + 1;
            if (loginIPNum >= LOGIN_IP_BAN_TIME_MAX.intValue()) {
                redisUtil.set(ipAddrLogin, loginIPNum, -1);
            } else {
                redisUtil.set(ipAddrLogin, loginIPNum, 7 * 24 * 60 * 60);
            }
        }
    }


    //设置频繁发送短信永久BANIP
    //1小时内频繁获取短信超过30次
    private void addSmsBanIP(String ipAddress) {
        //1小时内频繁获取短信超过30次
        String ipAddrSMS = "loginsmsban:" + ipAddress;
        if (!redisUtil.hasKey(ipAddrSMS)) {
            redisUtil.set(ipAddrSMS, 1, 60 * 60);
        } else {
            int loginIPNum = (int) redisUtil.get(ipAddrSMS);
            long addrSMSExpire = redisUtil.getExpire(ipAddrSMS);
            loginIPNum = loginIPNum + 1;
            if (loginIPNum >= LOGIN_SMS_BAN_TIME_MAX.intValue()) {
                redisUtil.set(ipAddrSMS, loginIPNum, -1);
            } else {
                redisUtil.set(ipAddrSMS, loginIPNum, addrSMSExpire);
            }
        }
    }

    //同一手机号每天获取短信不能超过40条
    private void addSmsMobileBan(String mobile) {

        //同一手机号每天获取短信不能超过40条
        String mobileSms = "loginmobileban:" + mobile;
        if (!redisUtil.hasKey(mobileSms)) {
            redisUtil.set(mobileSms, 1, 60 * 60 * 24);
        } else {
            int mobileNum = (int) redisUtil.get(mobileSms);
            long mobileExpire = redisUtil.getExpire(mobileSms);
            mobileNum = mobileNum + 1;
            if (mobileNum >= LOGIN_SMS_MOBILE_BAN_TIME_MAX.intValue()) {
                redisUtil.set(mobileSms, mobileNum, -1);
            } else {
                redisUtil.set(mobileSms, mobileNum, mobileExpire);
            }
        }
    }

    private boolean checkSmsBanIP(String ipAddress) {
        String ipAddrSMS = "loginsmsban:" + ipAddress;
        if (redisUtil.hasKey(ipAddrSMS)) {
            int number = (int) redisUtil.get(ipAddrSMS);
            if (number >= LOGIN_SMS_BAN_TIME_MAX.intValue()) {
                return true;
            }
        }

        return false;
    }

    private boolean checkSmsBanMobile(String mobile) {
        String mobileSms = "loginmobileban:" + mobile;
        if (redisUtil.hasKey(mobileSms)) {
            int number = (int) redisUtil.get(mobileSms);
            if (number >= LOGIN_SMS_MOBILE_BAN_TIME_MAX.intValue()) {
                return true;
            }
        }

        return false;
    }

    private boolean checkIp() {
        String ips = settingService.getSettingValueByTag("系统白名单");
        if (StringUtils.isEmpty(ips)) {
            return true;
        }
        String ipAddr = IPUtils.getIpAddr();
        if (StringUtils.isEmpty(ipAddr)) {
            return true;
        }
        return StringUtils.contains(ips, ipAddr);
    }


    private String checkLoginAddress(String ipAddrs) {
        if (StrUtil.isEmpty(ipAddrs)) {
            log.error("当前请求的IP地址不合法(1), {}", ipAddrs);
            return StrUtil.EMPTY;
        }

        String ipAddr = ipAddrs.split(",")[0];
        String address = StrUtil.EMPTY;
        try {
            address = this.amapService.ipConvertAddress(ipAddr);
        } catch (Exception e) {
            return "(忽略)高德接口访问异常";
        }

        //如果没配置验证区域的话忽略IP位置校验,把正确解析出来的地址直接返回
        if (StrUtil.isEmpty(this.requestAllow)) {
            return StrUtil.isEmpty(address) ? "(忽略)系统未配置有效区域" : address;
        }

        if (StrUtil.isEmpty(address)) {
            log.error("当前请求的IP地址不合法(2), {} {}", ipAddrs, address);
            return StrUtil.EMPTY;
        }

        String[] requestAllows = this.requestAllow.split(",");
        for (String addr : requestAllows) {
            if (address.contains(addr)) {
                return address;
            }
        }

        log.error("当前请求的IP地址不合法(3), {} {} {}", ipAddrs, requestAllows, address);
        return StrUtil.EMPTY;
    }

    @ApiOperation("(新)用户登录短信获取")
    @AutoLog("(新)用户登录短信获取")
    @RequestMapping(value = "/loginSms", method = RequestMethod.POST)
    public Result<JSONObject> loginSms(@RequestBody SysLoginModel sysLoginModel, HttpServletResponse response) throws Exception {

        log.info("用户获取登录短信参数, {}", JSONUtil.toJsonStr(sysLoginModel));
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        if (StrUtil.isEmpty(username)) {
            return result.error500("用户名不能为空");
        }

        if (isBannedIP()) {
            log.error("该账户IP登录异常，请联系管理员, {}", username);
            return result.error500("该账户IP登录异常，请联系管理员");
        }

        //Pattern pattern = Pattern.compile(CommonConstant.REGEX_SPECIAL_STRING);
        if (username.length() > 30 || !Pattern.matches(CommonConstant.REGEX_NORMAL_STRING, username)) {
            addLoginIP();
            log.info("用户名错误, {}", username);
            return result.error500("用户名错误");
        }

        if (ObjectUtil.isEmpty(sysLoginModel.getLoginType())) {
            return result.error500("登录类型不能为空");
        }

        SysUser sysUser = sysUserService.getUserByName(username);
        if (null == sysUser) {
            //如果通过username取不到，再通过手机号取一次
            sysUser = sysUserService.getUserByPhone(username);
            if (null == sysUser) {
                addLoginIP();
                log.info("用户不存在, {}", username);
                return result.error500("用户不存在");
            }
        }

        if (StrUtil.isEmpty(sysUser.getUType())) {
            return result.error500("该账号当前角色信息错误");
        }
        //1系统管理员 2 货主 3 货主子账号  4 司机  6业务管理员 7承运商
        if (!sysUser.getUType().equals(UserTypeEnum.管理员.getCode())
         && !sysUser.getUType().equals(UserTypeEnum.货主.getCode())
         && !sysUser.getUType().equals(UserTypeEnum.货主子账号.getCode())
         && !sysUser.getUType().equals(UserTypeEnum.业务管理员.getCode())
         && !sysUser.getUType().equals(UserTypeEnum.承运商.getCode())) {
            return result.error500("该账号当前角色不能登录");
        }

        if (StrUtil.isEmpty(sysUser.getPhone())) {
            log.error("该用户手机号验证失败, {}", JSONUtil.toJsonStr(sysUser));
            return result.error500("该用户手机号验证失败");
        }

        //2分钟获取一次短信
        long expire = redisUtil.getExpire("loginsms:" + sysUser.getPhone());
        if (expire > 8 * 60) {
            log.error("获取验证码过于频繁，请稍后获取, 有效时间{}", expire);
            return result.error500("获取验证码过于频繁，请稍后获取");
        }

        String captcha = RandomUtil.randomNumbers(6);
        Map<String, String> obj = new HashMap<>();
        obj.put("code", captcha);
        obj.put("number", "10");

        if (!sendSmsService.sendSms(sysUser.getPhone(), obj)) {
            return result.error500("短信登录服务不可用");
        }

        //验证码10分钟内有效
        redisUtil.set("loginsms:" + sysUser.getPhone(), captcha, 10 * 60);
        result.setSuccess(true);
        result.setCode(CommonConstant.SC_OK_200);
        String phoneEncode = sysUser.getPhone().replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2");
        result.setMessage("已向手机号码" + phoneEncode + "发送验证码成功,有效期10分钟");
        return result;
    }

    @ApiOperation("(新)用户名登录接口")
    @AutoLog("(新)密码登录接口")
    @RequestMapping(value = "/loginByUsername", method = RequestMethod.POST)
    public Result<JSONObject> loginByUsername(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request, HttpServletResponse response) throws Exception {

        log.info("[账密登录]用户名登录参数, {}", JSONUtil.toJsonStr(sysLoginModel));
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        //String phone    = sysLoginModel.getPhone();
        String password = sysLoginModel.getPassword();
        if (StrUtil.isEmpty(username)) {
            return result.error500("用户名不能为空");
        }

        if (StrUtil.isEmpty(password)) {
            return result.error500("密码不能为空");
        }

        if (ObjectUtil.isEmpty(sysLoginModel.getLoginType())) {
            return result.error500("登录类型不能为空");
        }

        if (isBannedIP()) {
            log.error("该账户IP登录异常，请联系管理员, {}", username);
            return result.error500("该账户IP登录异常，请联系管理员");
        }

        if (username.length() > 30 || !Pattern.matches(CommonConstant.REGEX_NORMAL_STRING, username)) {
            addLoginIP();
            log.info("用户名错误, {}", username);
            return result.error500("用户名错误");
        }

        SysUser sysUser = sysUserService.getUserByName(username);
        if (null == sysUser) {
            //如果通过username取不到，再通过手机号取一次
            sysUser = sysUserService.getUserByPhone(username);
            if (null == sysUser) {
                addLoginIP();
                log.info("当前用户不存在, {}", username);
                return result.error500("当前用户不存在");
            }

            username = sysUser.getUsername();
        }

        if (isBannedLogin(username)) {
            log.error("该账户因多次登录异常被临时冻结，请联系管理员, {}", username);
            return result.error500("该账户因多次登录异常被临时冻结，请联系管理员");
        }

        if (isDisableLogin(username)) {
            log.error("连续登陆失败5次，账户锁定30分钟！, {}", username);
            return result.error500("连续登陆失败5次，账户锁定30分钟！");
        }

        if (LOGIN_TYPE_PASSWORD == sysLoginModel.getLoginType().intValue()) {
            result = passwordLogin(username, password, sysLoginModel.getSmscode(), request, response);
        } else {
            log.error("登录方式错误");
            return result.error500("登录方式错误");
        }

        return result;
    }


    //密码登录处理
    private Result<JSONObject> passwordLogin(String username, String password, String smsCode, HttpServletRequest request, HttpServletResponse response) throws Exception {

        Result<JSONObject> result = new Result<JSONObject>();

        //update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题
        //前端密码加密，后端进行密码解密
        password = AesEncryptUtil.desEncrypt(password.replaceAll("%2B", "\\+")).trim();//密码解密

// Delete at 2023-12-14 for 不再使用验证码登录，换成短信+密码登录
//        //update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题
//        if (StrUtil.isEmpty(captcha)) {
//            return result.error500("验证码无效");
//        }
//
//        String lowerCaseCaptcha = captcha.toLowerCase();
//        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + checkKey, "utf-8");
//        Object checkCode = redisUtil.get(realKey);
//        //当进入登录页时，有一定几率出现验证码错误 #1714
//        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
//            result.error500("验证码错误");
//            return result;
//        }

        //手机号登录
        SysUser sysUser = null;
        if (username.matches(CommonConstant.REGEX_MOBILE)) {
            //1. 校验用户手机号是否有效
            sysUser = sysUserService.getUserByPhone(username);
            //2. 如果用户手机号查询失败，再拿手机号查一下用户名
            if (null == sysUser) {
                sysUser = sysUserService.getUserByName(username);
            }
            //3.如果都不存在，提示错误
            result = sysUserService.checkUserIsEffective(sysUser);
            if (!result.isSuccess()) {
                addLoginNum(username);
                //清空验证码
                //redisUtil.del(realKey);
                return result;
            }

            //通过手机号获取用户名用于下一步校验
            username = sysUser.getUsername();
        }
        //用户名登录
        else {
            sysUser = sysUserService.getUserByName(username);
            result = sysUserService.checkUserIsEffective(sysUser);
            if (!result.isSuccess()) {
                addLoginNum(username);
                //清空验证码
                //redisUtil.del(realKey);
                return result;
            }
        }

        //预先验证一下货主账号信息完整性
        //在该方法的最后有完整的校验
        if (sysUser.getUType().equals(UserTypeEnum.货主.getCode())) {
            HyCustomer customer = hyCustomerService.getCustomerByUserId(sysUser.getId());
            if (null == customer) {
                log.error("未找到货主信息 {}", JSONUtil.toJsonStr(sysUser));
                result.error500("未找到货主信息");
                return result;
            }

//            //检查选择的公司是否签合同
//            HyCustomerCompany customerCompany = hyCustomerCompanyService.getByCustomerId(customer.getId());
//            if (null == customerCompany) {
//                log.error("未找到货主签约信息 {}", JSONUtil.toJsonStr(sysUser));
//                result.error500("未找到货主签约信息");
//                return result;
//            }
        }

        if (sysUser.getUType().equals(UserTypeEnum.货主子账号.getCode())) {
            HyCustomerUser customerUser = hyCustomerUserService.getOne(new QueryWrapper<HyCustomerUser>().eq("user_id", sysUser.getId()));
            if (customerUser == null) {
                log.error("未找到货主子账号信息 {}", JSONUtil.toJsonStr(sysUser));
                return result.error500("未找到货主子账号信息");
            }

            if ("0".equals(customerUser.getIzUsed())) {
                log.error("账号已停用 {}", JSONUtil.toJsonStr(sysUser));
                return result.error500("账号已停用");
            }

            HyCustomer customer =  hyCustomerService.getById(customerUser.getCustomerId());
            if (customer == null){
                log.error("未找到子账号关联的货主信息 {}", JSONUtil.toJsonStr(sysUser));
                return result.error500("未找到子账号关联的货主信息");
            }
        }

        //1. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            log.warn("[账密登录]用户密码错误, {} {} {}", username, syspassword, userpassword);
            addLoginNum(username);
            //清空验证码
            //redisUtil.del(realKey);
            result.error500("用户名或密码错误");
            return result;
        }

        if (ObjectUtil.isEmpty(sysUser.getUType())) {
            return result.error500("当前登录用户的类别未指定");
        }

        //2.如果是管理员用户增加白名单验证
        String loginAddr = StrUtil.EMPTY;
        if (sysUser.getUType().equals(UserTypeEnum.管理员.getCode())) {
            String ipAddrs = IPUtils.getIpAddr();
            loginAddr = checkLoginAddress(ipAddrs);
            if (StrUtil.isEmpty(loginAddr)) {
                addLoginNum(username);
                baseCommonService.addLog("[账密登录]用户名: " + username  + " 登录地区：" + loginAddr + " ,登录区域错误！", CommonConstant.LOG_TYPE_1, null);
                return result.error500("您所在的区域不允许登录系统");
            }

            log.info("系统用户校验IP白名单, {} 登录地址:{}, 登录IP：{} ，白名单：{}", username, loginAddr, ipAddrs, settingService.getSettingValueByTag("系统白名单"));
            if (!checkIp()) {
                log.warn("系统用户IP校验不通过{}", username);
                return result.error500("当前角色限制IP登陆，请联系管理员");
            }
        }

        log.info("[账密登录]用户发起登录, {}", JSONUtil.toJsonStr(sysUser));
        //3.校验免短信验证信息
        /*if (ObjectUtil.isEmpty(smsCode)) {
            String cookieLoginRemember = StrUtil.EMPTY;
            String encryptUsername = SmUtil.sm3(username + this.paramsId);
            Cookie[] cookies = request.getCookies();
            if (null == cookies) {
                result.setCode(406);
                result.setMessage("用户名或密码错误!");
                log.info("Cookie为空, {} {}", encryptUsername, username);
                return result;
            }

            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(encryptUsername)) {
                    cookieLoginRemember = cookie.getValue();
                }
            }

            if (StrUtil.isEmpty(cookieLoginRemember)) {
                result.setCode(406);
                result.setMessage("用户名或密码错误.");
                log.info("无用户校验信息, {} {}", encryptUsername, username);
                return result;
            }

            Object redisLoginRemember = redisUtil.get("loginremember:" + encryptUsername);
            if (ObjectUtil.isEmpty(redisLoginRemember) || !cookieLoginRemember.equals(redisLoginRemember)) {
                result.setCode(406);
                result.setMessage("用户名或密码错误。");
                log.error("用户免短信校验失败, {} {}", redisLoginRemember, cookieLoginRemember);
                addLoginNum(username);
                return result;
            }

            log.info("用户免短信校验完成, {} {} {} {}", username, encryptUsername, redisLoginRemember, cookieLoginRemember);
        } else {
            //4.校验手机验证码是否正确
            //Added start at 2023-12-14 for 判断短信验证，去掉验证码验证
            Object redisSmsCode = redisUtil.get("loginsms:" + sysUser.getPhone());
            if (ObjectUtil.isEmpty(redisSmsCode)) {
                addLoginNum(username);
                return result.error500("该用户验证码已过期，请重新获取");
            }

            if (!smsCode.equals(redisSmsCode.toString())) {
                addLoginNum(username);
                return result.error500("用户验证码校验失败");
            }
            //Added end at 2023-12-14 for 判断短信验证，去掉验证码验证
        }*/

        //1系统用户 2 货主 3 货主子账号  4 司机 5 承运商 6业务管理员
        if (!sysUser.getUType().equals(UserTypeEnum.管理员.getCode())
         && !sysUser.getUType().equals(UserTypeEnum.货主.getCode())
         && !sysUser.getUType().equals(UserTypeEnum.货主子账号.getCode())
         && !sysUser.getUType().equals(UserTypeEnum.业务管理员.getCode())
         && !sysUser.getUType().equals(UserTypeEnum.承运商.getCode())) {
            addLoginNum(username);
            //清空验证码
            //redisUtil.del(realKey);
            result.error500("该账号当前角色不能登录");
            return result;
        }

        if (!"admin".equals(sysUser.getUsername())) {
            //获取用户数据权限
            List<HyProject> list = hyProjectService.list(new QueryWrapper<HyProject>().like("project_users", sysUser.getId()));
            String ids = "";
            for (HyProject hyProject : list) {
                String[] split = hyProject.getProjectEnterprises().split(",");
                for (int i = 0; i < split.length; i++) {
                    ids = ids + "," + split[i];
                }
            }
            redisUtil.set("dataPermission:" + sysUser.getId(), ids);
        }

        //等保使用 admin 密码 90天过期
        if ("admin".equals(username)) {
            Date overdueTime =  new Date();
            if (sysUser.getOverdueTime() != null) {
                overdueTime = sysUser.getOverdueTime();
            }
            Date nowData = new Date();
            if (overdueTime != null) {
                if (nowData.getTime() > overdueTime.getTime()) {//过期了
                    result.setCode(999);
                    result.setMessage("密码已失效!");
                    return result;
                }
            }
        }

        //用户登录信息
        sysUserService.userInfo(sysUser, result);
        userUtil.CheckUserRole(sysUser, result);

        //货主角色登录，需要验证签约信息
        if (sysUser.getUType().equals(UserTypeEnum.货主.getCode())) {
            HyCustomer customer = userUtil.CheckUserRole(sysUser, result);
            if (customer == null) {
                result.error500("没有货主信息");
                return result;
            }

            //配置货主登录时是否需要签约
            if ("1".equals(customerSign)) {
                //检查选择的公司是否签合同
                HyCustomerCompany customerCompany = hyCustomerCompanyService.getByCustomerId(customer.getId());
                if (customerCompany == null) {
                    result.error500("未找到货主签约信息");
                    return result;
                }
                //检查是否有公司信息
                HyCompany company = hyCompanyService.getById(customerCompany.getCompanyId());
                if (company == null) {
                    result.error500("公司信息不能存在");
                    return result;
                }
            }
        }

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        log.info("[账密登录]用户名: {}, 登录地区：{} 登录成功！", username, loginAddr);
        baseCommonService.addLog("[账密登录]用户名: " + username  + " 登录地区：" + loginAddr + " ,登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);

        //登录成功后，清除登录失败次数
        redisUtil.del("loginban:" + username);

        //登录成功后，缓存登录地址和IP
        redisUtil.set("loginUserAddr:" + loginUser.getUsername(), loginAddr);
        redisUtil.set("loginUserIP:" + loginUser.getUsername(), IPUtils.getIpAddr());

        setUserCookie(username, response);
        return result;
    }

    @ApiOperation("(新)记录登录设备")
    @AutoLog("(新)记录登录设备")
    @RequestMapping(value = "/remember/{fingerPrint}", method = RequestMethod.GET)
    public Result rememberLoginUser(@PathVariable String fingerPrint, HttpServletResponse response) {

        if (StrUtil.isEmpty(fingerPrint)) {
            return Result.error("无效的参数");
        }

        LoginUser loginUser = UserUtil.getLoginUser();
        String username = loginUser.getUsername();
        String encryptUsername = SmUtil.sm3(username + this.paramsId);
        //如果配置了 requestAllowLongDays，为7天有效期
        if (StrUtil.isNotEmpty(this.requestAllowLongDays)) {
            redisUtil.set("loginremember:" + encryptUsername, fingerPrint, 7 * 60 * 60 * 24);
            log.info("记录7天免短信登录 {} {} {}", username, encryptUsername, fingerPrint);
        } else {
            //记录3天免短信登录
            redisUtil.set("loginremember:" + encryptUsername, fingerPrint, 3 * 60 * 60 * 24);
            log.info("记录3天免短信登录 {} {} {}", username, encryptUsername, fingerPrint);
        }
        baseCommonService.addLog("[记录设备]用户名: " + username + " ," + fingerPrint, CommonConstant.LOG_TYPE_2, null, loginUser);

        Cookie cookie= new Cookie(encryptUsername, fingerPrint);
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        if (StrUtil.isNotEmpty(this.requestAllowLongDays)) {
            cookie.setMaxAge(7 * 60 * 60 * 24);
        } else {
            cookie.setMaxAge(3 * 60 * 60 * 24);
        }

        ((HttpServletResponse)response).addCookie(cookie);
        return Result.OK();
    }


    private void setUserCookie(String username, HttpServletResponse response) {
        Cookie cookie= new Cookie(CommonConstant.X_PC_COOKIE, MD5Util.MD5Encode(username, "utf-8"));
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(60 * 60 * 24 * 30);
        ((HttpServletResponse)response).addCookie(cookie);
        log.info("PC登录设置cookie - X_ACESS_COOKIE - {}", cookie.getValue());

        return;
    }

//    @ApiOperation("新短信登录接口")
//    @AutoLog("(新)用户短信登录")
//    @RequestMapping(value = "/loginBySMS", method = RequestMethod.POST)
//    public Result<JSONObject> loginBySMS(@RequestBody SysLoginModel sysLoginModel, HttpServletResponse response) throws Exception {
//
//        log.info("[短信登录]用户短信登录接口, {}", JSONUtil.toJsonStr(sysLoginModel));
//        Result<JSONObject> result = new Result<JSONObject>();
//        String phone   = sysLoginModel.getPhone();
//        String smscode = sysLoginModel.getSmscode();
//        if (StrUtil.isEmpty(phone) || phone.length() != 11) {
//            return result.error500("手机号长度错误");
//        }
//        if (!phone.matches(CommonConstant.REGEX_MOBILE)) {
//            return result.error500("手机号格式错误");
//        }
//
//        //如果连续使用不存在的手机号登录超30次，将该IP临时封禁
//        SysUser sysUser = sysUserService.getUserByPhone(phone);
//        if (null == sysUser) {
//            addLoginIP();
//            return result.error500("用户不存在");
//        }
//
//        if (isBannedIP()) {
//            log.error("该账户IP登录异常被临时冻结，请联系管理员, {}", phone);
//            return result.error500("该账户IP登录异常被临时冻结，请联系管理员");
//        }
//
//        if (isBannedLogin(phone)) {
//            log.error("该账户因多次登录异常被临时冻结，请联系管理员, {}", phone);
//            return result.error500("该账户因多次登录异常被临时冻结，请联系管理员");
//        }
//
//        if (isDisableLogin(phone)) {
//            return result.error500("连续登陆失败5次，账户锁定30分钟！");
//        }
//
//        if (ObjectUtil.isEmpty(sysLoginModel.getLoginType())) {
//            return result.error500("登录方式错误");
//        }
//
//        if (StrUtil.isEmpty(smscode)) {
//            return result.error500("手机验证码不能为空");
//        }
//
//        //expire=-2 没有该key
//        //expire=-1 不过期
//        long expire = redisUtil.getExpire(phone);
//        //有效期没超过2分钟  (5-2)*60
//        if (expire < 3 * 60) {
//            addLoginNum(phone);
//            log.warn("[短信登录]验证码已过期, {}", phone);
//            return result.error500("验证码已过期");
//        }
//
//        Object code = redisUtil.get(phone);
//        if (!smscode.equals(code)) {
//            addLoginNum(phone);
//            log.warn("[短信登录]验证码错误, {}", phone);
//            result.setMessage("手机验证码错误");
//            return result;
//        }
//        if (LOGIN_TYPE_SMS == sysLoginModel.getLoginType().intValue()) {
//            result = smsLogin(phone, response);
//        } else {
//            log.error("[短信登录]短信登录方式错误");
//            return result.error500("登录方式错误");
//        }
//
//        return result;
//    }


//    private Result<JSONObject> smsLogin(String phone, HttpServletResponse response) {
//        Result<JSONObject> result = new Result<JSONObject>();
//        //校验用户有效性
//        SysUser sysUser = sysUserService.getUserByPhone(phone);
//        result = sysUserService.checkUserIsEffective(sysUser);
//        if (!result.isSuccess()) {
//            addLoginNum(phone);
//            return result;
//        }
//
//        if (ObjectUtil.isEmpty(sysUser.getUType())) {
//            return result.error500("当前登录用户的类别未指定");
//        }
//
//        //如果是管理员用户增加白名单验证
//        String loginAddr = StrUtil.EMPTY;
//        if (sysUser.getUType().equals(UserTypeEnum.管理员.getCode())) {
//            String ipAddrs = IPUtils.getIpAddr();
//            loginAddr = checkLoginAddress(ipAddrs);
//            if (StrUtil.isEmpty(loginAddr)) {
//                addLoginNum(phone);
//                baseCommonService.addLog("[短信登录]用户名: " + phone  + " 登录地区：" + loginAddr + " ,登录区域错误！", CommonConstant.LOG_TYPE_1, null);
//                return result.error500("您所在的区域不允许登录系统");
//            }
//
//            log.info("系统用户校验IP白名单, {} 登录地址:{}, 登录IP：{} ，白名单：{}", sysUser.getUsername(), loginAddr, ipAddrs, settingService.getSettingValueByTag("系统白名单"));
//            if (!checkIp()) {
//                log.warn("系统用户IP校验不通过{}", sysUser.getUsername());
//                return result.error500("当前角色限制IP登陆，请联系管理员");
//            }
//
//            //管理员登录成功后，清除登录失败次数
//            redisUtil.del("logibnan:" + phone);
//        }
//
//        log.info("[短信登录]用户短信登录, {}", JSONUtil.toJsonStr(sysUser));
//        //1系统用户 2 货主 3 货主子账号  4 司机 5 承运商
//        if (!sysUser.getUType().equals(UserTypeEnum.管理员.getCode())
//         && !sysUser.getUType().equals(UserTypeEnum.货主.getCode())
//         && !sysUser.getUType().equals(UserTypeEnum.货主子账号.getCode())) {
//            addLoginNum(phone);
//            //清空验证码
//            redisUtil.del(phone);
//            return result.error500("该账号当前角色不能登录");
//        }
//
//        if (!"admin".equals(sysUser.getUsername())) {
//            //获取用户数据权限
//            List<HyProject> list = hyProjectService.list(new QueryWrapper<HyProject>().like("project_users", sysUser.getId()));
//            String ids = "";
//            for (HyProject hyProject : list) {
//                String[] split = hyProject.getProjectEnterprises().split(",");
//                for (int i = 0; i < split.length; i++) {
//                    ids = ids + "," + split[i];
//                }
//            }
//            redisUtil.set("dataPermission:" + sysUser.getId(), ids);
//        }
//
//        //等保使用 admin 密码 90天过期
//        if ("admin".equals(sysUser.getUsername())) {
//            Date overdueTime =  new Date();
//            if (sysUser.getOverdueTime() != null) {
//                overdueTime = sysUser.getOverdueTime();
//            }
//            Date nowData = new Date();
//            if (overdueTime != null) {
//                if (nowData.getTime() > overdueTime.getTime()) {//过期了
//                    result.setCode(999);
//                    result.setMessage("密码已过期!");
//                    return result;
//                }
//            }
//        }
//
//        //用户信息
//        sysUserService.userInfo(sysUser, result);
//        userUtil.CheckUserRole(sysUser, result);
//
//        //货主角色登录，需要验证签约信息
//        if (sysUser.getUType().equals(UserTypeEnum.货主.getCode())) {
//            HyCustomer customer = userUtil.CheckUserRole(sysUser, result);
//            if (customer == null) {
//                return result.error500("没有货主信息");
//            }
//            //检查选择的公司是否签合同
//            HyCustomerCompany customerCompany = hyCustomerCompanyService.getByCustomerId(customer.getId());
//            if (customerCompany == null) {
//                return  result.error500("未找到货主签约信息");
//            }
//            HyCompany company = hyCompanyService.getById(customerCompany.getCompanyId());
//            if (company == null) {
//                return result.error500("公司信息不能存在");
//            }
//        }
//
//        setUserCookie(sysUser.getUsername(), response);
//        //添加日志
//        baseCommonService.addLog("[短信登录]用户名: " + sysUser.getUsername() + " 登录区域：" + loginAddr + " ,登录成功！", CommonConstant.LOG_TYPE_1, null);
//        return result;
//    }


//    @ApiOperation("登录接口")
//    @RequestMapping(value = "/login", method = RequestMethod.POST)
//    public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel) throws Exception {
//        Result<JSONObject> result = new Result<JSONObject>();
//        if (!checkIp()) {
//            result.error500("ip限制登陆，请联系管理员");
//            return result;
//        }
//
//        String username = sysLoginModel.getUsername();
//        if (StringUtils.isEmpty(username)) {
//            result.error500("用户名不能为空");
//            return result;
//        }
//
//        if (isDisableLogin(username)) {
//            result.error500("连续登陆失败5次，账户锁定10分钟！");
//            return result;
//        }
//
//        String password = sysLoginModel.getPassword();
//        if (StringUtils.isEmpty(password)) {
//            result.error500("密码不能为空");
//            return result;
//        }
//        //update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题
//        //前端密码加密，后端进行密码解密
//        password = AesEncryptUtil.desEncrypt(password.replaceAll("%2B", "\\+")).trim();//密码解密
//        //update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题
//
//        //update-begin-author:taoyan date:20190828 for:校验验证码
//        String captcha = sysLoginModel.getCaptcha();
//        if (captcha == null) {
//            result.error500("验证码无效");
//            return result;
//        }
//        String lowerCaseCaptcha = captcha.toLowerCase();
//        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + sysLoginModel.getCheckKey(), "utf-8");
//        Object checkCode = redisUtil.get(realKey);
//        //当进入登录页时，有一定几率出现验证码错误 #1714
//        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
//            result.error500("验证码错误");
//            return result;
//        }
//        //update-end-author:taoyan date:20190828 for:校验验证码
//
//        //1. 校验用户是否有效
//        //update-begin-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
//        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(SysUser::getUsername, username);
//        SysUser sysUser = sysUserService.getOne(queryWrapper);
//
//        //update-end-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
//        result = sysUserService.checkUserIsEffective(sysUser);
//        if (!result.isSuccess()) {
//            //清空验证码
//            redisUtil.del(realKey);
//            return result;
//        }
//
//        //2. 校验用户名或密码是否正确
//        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
//        String syspassword = sysUser.getPassword();
//        if (!syspassword.equals(userpassword)) {
//            addLoginNum(username);
//            //清空验证码
//            redisUtil.del(realKey);
//            result.error500("用户名或密码错误");
//            return result;
//        }
//        //1系统用户 2 货主 3 货主子账号  4 司机 5 承运商
//        if (!"1".equals(sysUser.getUType()) && !"5".equals(sysUser.getUType())) {
//            addLoginNum(username);
//            //清空验证码
//            redisUtil.del(realKey);
//            result.error500("不是管理账号,不能登录");
//            return result;
//        }
//
//        if (!"admin".equals(sysUser.getUsername())) {
//            //获取用户数据权限
//            List<HyProject> list = hyProjectService.list(new QueryWrapper<HyProject>().like("project_users", sysUser.getId()));
//            String ids = "";
//            for (HyProject hyProject : list) {
//                String[] split = hyProject.getProjectEnterprises().split(",");
//                for (int i = 0; i < split.length; i++) {
//                    ids = ids + "," + split[i];
//                }
//            }
//            redisUtil.set("dataPermission:" + sysUser.getId(), ids);
//        }
//
//        // TODO: 2022/8/4 0004 等保使用 admin 密码 90天过期
//        if ("admin".equals(username)) {
//            Date overdueTime =  new Date();
//            if (sysUser.getOverdueTime() != null) {
//                overdueTime = sysUser.getOverdueTime();
//            }
//            Date nowData = new Date();
//            if (overdueTime != null) {
//                if (nowData.getTime() > overdueTime.getTime()) {//过期了
//                    result.setCode(999);
//                    result.setMessage("密码已过期!");
//                    return result;
//                }
//            }
//
//        }
//
//        //用户登录信息
//        sysUserService.userInfo(sysUser, result);
//        userUtil.CheckUserRole(sysUser, result);
//        //update-begin--Author:wangshuai  Date:20200714  for：登录日志没有记录人员
//        LoginUser loginUser = new LoginUser();
//        BeanUtils.copyProperties(sysUser, loginUser);
//        baseCommonService.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
//        //update-end--Author:wangshuai  Date:20200714  for：登录日志没有记录人员
//        return result;
//    }


    /**
     * PC端货主注册
     * @param sysLoginModel
     * @return
     */
    @AutoLog(value = "货主注册")
    @ApiOperation(value="货主注册", notes="货主注册")
    @RequestMapping(value = "/customer/register", method = RequestMethod.POST)
    public Result<?> register(@RequestBody CustomerSysLoginModel sysLoginModel) {

        String phone = sysLoginModel.getPhone();
        String smscode = sysLoginModel.getSmscode();
        String password = sysLoginModel.getPassword();
        Object code = redisUtil.get(phone);

        SysUser sysUser = this.sysUserService.getUserByPhone(phone);
        if (sysUser != null) {
            return Result.error("该手机号已注册");
        }

        if (!smscode.equals(code)) {
            log.error("手机验证码错误， {} {}", smscode, code);
            return Result.error("手机验证码错误");
        }

        if (StrUtil.isEmpty(password)) {
            return Result.error("密码不能为空");
        }

        if (StrUtil.isEmpty(sysLoginModel.getCustomerType())) {
            return Result.error("货主类型未选择");
        }

        Result r = this.hyCustomerService.registerCustomer(sysLoginModel);
        if (!r.getCode().equals(CommonConstant.SC_OK_200)) {
            return r;
        }

        //添加日志
        baseCommonService.addLog("货主注册: " +phone + ",注册成功！",
                CommonConstant.LOG_TYPE_1, null);
        return Result.OK("注册成功，等待管理员审核");
    }


//    @ApiOperation("货主登录接口")
//    @RequestMapping(value = "/customerlogin", method = RequestMethod.POST)
//    public Result<JSONObject> customerlogin(@RequestBody SysLoginModel sysLoginModel) throws Exception {
//        Result<JSONObject> result = new Result<JSONObject>();
//        String phone = sysLoginModel.getUsername();
//        String password = sysLoginModel.getPassword();
//        if (StringUtils.isEmpty(phone)) {
//            result.error500("用户名不能为空");
//            return result;
//        }
//        if (isDisableLogin(phone)) {
//            result.error500("连续登陆失败5次，账户锁定10分钟！");
//            return result;
//        }
//
//        if (StringUtils.isEmpty(password)) {
//            result.error500("密码不能为空");
//            return result;
//        }
//        //update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题
//        //前端密码加密，后端进行密码解密
//        password = AesEncryptUtil.desEncrypt(password.replaceAll("%2B", "\\+")).trim();//密码解密
//        //update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题
//
//        //update-begin-author:taoyan date:20190828 for:校验验证码
//        String captcha = sysLoginModel.getCaptcha();
//        if (captcha == null) {
//            result.error500("验证码无效");
//            return result;
//        }
//        String lowerCaseCaptcha = captcha.toLowerCase();
//        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + sysLoginModel.getCheckKey(), "utf-8");
//        Object checkCode = redisUtil.get(realKey);
//        //当进入登录页时，有一定几率出现验证码错误 #1714
//        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
//            result.error500("验证码错误");
//            return result;
//        }
//        //update-end-author:taoyan date:20190828 for:校验验证码
//
//        //1. 校验用户是否有效
//        SysUser sysUser = sysUserService.getUserByPhone(phone);
//        result = sysUserService.checkUserIsEffective(sysUser);
//        if (!result.isSuccess()) {
//            //清空验证码
//            redisUtil.del(realKey);
//            return result;
//        }
//
//        //2. 校验用户名或密码是否正确
//        String username = sysUser.getUsername();
//        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
//        String syspassword = sysUser.getPassword();
//        if (!syspassword.equals(userpassword)) {
//            addLoginNum(phone);
//            //清空验证码
//            redisUtil.del(realKey);
//            result.error500("用户名或密码错误");
//            return result;
//        }
//        //1系统用户 2 货主 3 货主子账号  4 司机
//        if (!"2".equals(sysUser.getUType()) && !"3".equals(sysUser.getUType())) {
//            addLoginNum(phone);
//            //清空验证码
//            redisUtil.del(realKey);
//            result.error500("不是货主账号,不能登录");
//            return result;
//        }
//
//        //用户登录信息
//        sysUserService.userInfo(sysUser, result);
//        HyCustomer customer = userUtil.CheckUserRole(sysUser, result);
//        if (customer == null) {
//            result.error500("没有货主信息");
//            return result;
//        }
//        //检查选择的公司是否签合同
//        HyCustomerCompany customerCompany = hyCustomerCompanyService.getByCustomerId(customer.getId());
//        if (customerCompany == null) {
//            result.error500("未找到货主签约信息");
//            return result;
//        }
//        HyCompany company = hyCompanyService.getById(customerCompany.getCompanyId());
//        if (company == null) {
//            result.error500("公司信息不能存在");
//            return result;
//        }
//
//        //update-begin--Author:wangshuai  Date:20200714  for：登录日志没有记录人员
//        LoginUser loginUser = new LoginUser();
//        BeanUtils.copyProperties(sysUser, loginUser);
//
//        baseCommonService.addLog("用户名: " + phone + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
//        //update-end--Author:wangshuai  Date:20200714  for：登录日志没有记录人员
//        return result;
//    }

    /**
     * 退出登录
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/logout")
    public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        //用户退出逻辑
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isEmpty(token)) {
            return Result.error("退出登录失败！");
        }
        String username = JwtUtil.getUsername(token);
        LoginUser sysUser = sysBaseAPI.getUserByName(username);
        if (sysUser != null) {
            //update-begin--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
            baseCommonService.addLog("用户名: " + sysUser.getRealname() + ",退出成功！", CommonConstant.LOG_TYPE_1, null, sysUser);
            //update-end--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
//			log.info(" 用户名:  "+sysUser.getRealname()+",退出成功！ ");
            //清空用户登录Token缓存
            redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
//			redisUtil.del(CommonConstant.PREFIX_CUSTOMERID + token);
            //清空用户登录Shiro权限缓存
            redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
            //清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
            redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
            //调用shiro的logout
            SecurityUtils.getSubject().logout();
            return Result.ok("退出登录成功！");
        } else {
            return Result.error("Token无效!");
        }
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("loginfo")
    public Result<JSONObject> loginfo() {
        Result<JSONObject> result = new Result<JSONObject>();
        JSONObject obj = new JSONObject();
        //update-begin--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        // 获取一天的开始和结束时间
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date dayStart = calendar.getTime();
        calendar.add(Calendar.DATE, 1);
        Date dayEnd = calendar.getTime();
        // 获取系统访问记录
        Long totalVisitCount = logService.findTotalVisitCount();
        obj.put("totalVisitCount", totalVisitCount);
        Long todayVisitCount = logService.findTodayVisitCount(dayStart, dayEnd);
        obj.put("todayVisitCount", todayVisitCount);
        Long todayIp = logService.findTodayIp(dayStart, dayEnd);
        //update-end--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        obj.put("todayIp", todayIp);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("visitInfo")
    public Result<List<Map<String, Object>>> visitInfo() {
        Result<List<Map<String, Object>>> result = new Result<List<Map<String, Object>>>();
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date dayEnd = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, -7);
        Date dayStart = calendar.getTime();
        List<Map<String, Object>> list = logService.findVisitCount(dayStart, dayEnd);
        result.setResult(oConvertUtils.toLowerCasePageList(list));
        return result;
    }


    /**
     * 登陆成功选择用户当前部门
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/selectDepart", method = RequestMethod.PUT)
    public Result<JSONObject> selectDepart(@RequestBody SysUser user) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = user.getUsername();
        if (oConvertUtils.isEmpty(username)) {
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            username = sysUser.getUsername();
        }
        String orgCode = user.getOrgCode();
        this.sysUserService.updateUserDepart(username, orgCode);
        SysUser sysUser = sysUserService.getUserByName(username);
        JSONObject obj = new JSONObject();
        obj.put("userInfo", sysUser);
        result.setResult(obj);
        return result;
    }

    /**
     * 短信登录接口
     *
     * @param jsonObject
     * @return
     */
    @AutoLog("短信发送接口")
    @PostMapping(value = "/sms")
    public Result<JSONObject> sms(HttpServletRequest request, @RequestBody JSONObject jsonObject) {

        Result<JSONObject> result = new Result<>();
        result.setSuccess(false);

        String mobile = jsonObject.get("mobile").toString();
        if (mobile.length() != 11) {
            result.error500("手机号应为11位数。");
        }
        if (!mobile.matches(CommonConstant.REGEX_MOBILE)) {
            result.error500("手机号格式错误！");
        }
        //手机号模式 登录模式: "2"  注册模式: "1"
        String smsmode = jsonObject.get("smsmode").toString();
//		log.info(mobile);
        if (oConvertUtils.isEmpty(mobile)) {
            result.error500("手机号不允许为空！");
            return result;
        }

        //防止恶意刷短信，统计IP请求短信的次数
        String ipAddrLogin = IPUtils.getIpAddr(request);
        log.info("IP: {} 向手机号{}发送短信", ipAddrLogin, mobile);
        //可能存在多个IP，所以都统计
        for (String ip : ipAddrLogin.split(",")) {
            ip = ip.trim();
            //巨睿WAF特殊处理192.168.0.194,内网WAF IP不作为BANIP
            /*if (ip.equals("192.168.0.194")) {
                break;
            }*/
            if (ip.contains("192.168")) {
                break;
            }
            if (checkSmsBanIP(ip)) {
                log.error("IP: {} 地址判定向手机号{} 恶意发送短信已被冻结", ip, mobile);
                return result.error500("该ip多次向"+mobile+"发送短信判定为恶意盗刷短信已被冻结，请联系管理员");
            }

            if (checkSmsBanMobile(mobile)) {
                log.error("手机号 {} 超出每日短信请求次数已被冻结,IP地址{}", mobile, ip);
                return result.error500("该手机号获取短信超出每日短信请求次数已被冻结，请联系管理员");
            }

            this.addSmsBanIP(ip);
            this.addSmsMobileBan(mobile);
        }

        //如果开启短信随机校验码
        String vehicleTrackSwitch = this.settingService.getSettingValueByTag2("sms_random_check");
        if ("1".equals(vehicleTrackSwitch)) {
            String smsRandomNumber = jsonObject.getString("randomNumber");
            String smsRandomKey = jsonObject.getString("randomKey");

            if (StrUtil.isEmpty(smsRandomNumber) || StrUtil.isEmpty(smsRandomKey)) {
                log.warn("验证码无效,随机验证码为空 {} - {}", smsRandomNumber, smsRandomKey);
                result.error500("验证码无效");
                return result;
            }
            String lowerCaseRandomNumber = smsRandomNumber.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseRandomNumber + smsRandomKey, "utf-8");
            Object checkCode = redisUtil.get(realKey);
            //校验获取短信时的随机验证码，如果失败不允许调用短信接口
            if (checkCode == null || !checkCode.toString().equals(lowerCaseRandomNumber)) {
                log.warn("随机验证码错误 {} - {}", checkCode, lowerCaseRandomNumber);
                result.error500("验证码错误");
                return result;
            }
        }

        //expire=-2 没有该key
        //expire=-1 不过期
        long expire = redisUtil.getExpire(mobile);
        //有效期没超过2分钟  (5-2)*60
        if (expire > 3 * 60) {
            log.warn("手机号 {} 获取短信请求频繁,剩余{}秒", mobile, expire);
            result.error500("获取验证码间隔为2分钟，请稍后重试！");
            return result;
        }

        //随机数
        String captcha = RandomUtil.randomNumbers(6);
        Map<String, String> obj = new HashMap<>();
        obj.put("code", captcha);
        obj.put("number", "10");
        try {
            boolean b = false;
            //注册模板
            if (CommonConstant.SMS_TPL_TYPE_1.equals(smsmode)) {
                SysUser sysUser = sysUserService.getUserByPhone(mobile);
                if (sysUser != null) {
                    result.error500(" 手机号已经注册，请直接登录！");
                    baseCommonService.addLog("手机号已经注册，请直接登录！", CommonConstant.LOG_TYPE_1, null);
                    return result;
                }
                b = sendSmsService.sendSms(mobile, obj);
                //b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.REGISTER_TEMPLATE_CODE);
            } else {
                //登录模式，校验用户有效性
                SysUser sysUser = sysUserService.getUserByPhone(mobile);
                if (sysUser == null) {
                    log.warn("[登录]该用户不存在或未绑定手机号 {} ", mobile);
                    result.error500("该用户不存在或未绑定手机号");
                    return result;
                }
                result = sysUserService.checkUserIsEffective(sysUser);
                if (!result.isSuccess()) {
                    String message = result.getMessage();
                    if ("该用户不存在，请注册".equals(message)) {
                        log.warn("[登录]该用户不存在，请注册 {} ", mobile);
                        result.error500("该用户不存在或未绑定手机号");
                    }
                    return result;
                }

                /**
                 * smsmode 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
                 */
                if (CommonConstant.SMS_TPL_TYPE_0.equals(smsmode)) {
                    //登录模板
                    b = sendSmsService.sendSms(mobile, obj);
                    //b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.LOGIN_TEMPLATE_CODE);
                } else if (CommonConstant.SMS_TPL_TYPE_2.equals(smsmode)) {
                    //忘记密码模板
                    b = sendSmsService.sendSms(mobile, obj);
                    //b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.FORGET_PASSWORD_TEMPLATE_CODE);
                }
            }

            if (b == false) {
                result.error500("短信验证码发送失败,请稍后重试");
                return result;
            }
            //验证码5分钟内有效
            redisUtil.set(mobile, captcha, 5 * 60);
            //update-begin--Author:scott  Date:20190812 for：issues#391
            //result.setResult(captcha);
            //update-end--Author:scott  Date:20190812 for：issues#391
            result.setSuccess(true);
            result.setCode(CommonConstant.SC_OK_200);
            result.setMessage("发送成功！");

        } catch (ClientException e) {
            e.printStackTrace();
            result.setMessage(" 短信接口未配置，请联系管理员！");
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            result.error500(e.getMessage());
            return result;
        }
        return result;
    }

    @AutoLog("短信发送接口SMS2")
    @PostMapping(value = "/sms2")
    public Result<?> sms2(HttpServletRequest request) {
        //获取当前系统用户
        LoginUser loginUser = UserUtil.getLoginUser();
        if (loginUser == null) {
            return Result.error("未获取到登录信息");
        }
        String phone = loginUser.getPhone();
        if (StringUtils.isEmpty(phone)) {
            return Result.error("没有设置手机号");
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("mobile", phone);
        jsonObject.put("smsmode", "2");
        return sms(request, jsonObject);
    }


    /**
     * 手机号登录接口
     *
     * @param jsonObject
     * @return
     */
    @ApiOperation("手机号登录接口")
    @PostMapping("/phoneLogin")
    public Result<JSONObject> phoneLogin(@RequestBody JSONObject jsonObject) {
        Result<JSONObject> result = new Result<JSONObject>();
        if (!checkIp()) {
            result.error500("ip限制登陆，请联系管理员");
            return result;
        }
        String phone = jsonObject.getString("mobile");
        if (StringUtils.isEmpty(phone)) {
            result.error500("手机号不能为空");
            return result;
        }
        if (isDisableLogin(phone)) {
            result.error500("连续登陆失败5次，账户锁定10分钟！");
            return result;
        }
        String smscode = jsonObject.getString("captcha");
        if (StringUtils.isEmpty(smscode)) {
            result.error500("手机验证码不能为空");
            return result;
        }
        Object code = redisUtil.get(phone);
        if (!smscode.equals(code)) {
            addLoginNum(phone);
            result.setMessage("手机验证码错误");
            return result;
        }

        //校验用户有效性
        SysUser sysUser = sysUserService.getUserByPhone(phone);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }
        //1系统用户 2 货主 3 货主子账号  4 司机
        if (!"1".equals(sysUser.getUType())) {
            addLoginNum(phone);
            result.error500("不是管理账号,不能登录");
            return result;
        }

        //用户信息
        sysUserService.userInfo(sysUser, result);
        userUtil.CheckUserRole(sysUser, result);
        //添加日志
        baseCommonService.addLog("用户名: " + sysUser.getUsername() + ",登录成功！", CommonConstant.LOG_TYPE_1, null);
        return result;
    }

    /**
     * 获取加密字符串
     *
     * @return
     */
    @GetMapping(value = "/getEncryptedString")
    public Result<Map<String, String>> getEncryptedString() {
        Result<Map<String, String>> result = new Result<Map<String, String>>();
        Map<String, String> map = new HashMap<String, String>();
        map.put("key", EncryptedString.key);
        map.put("iv", EncryptedString.iv);
        result.setResult(map);
        return result;
    }

    /**
     * 后台生成图形验证码 ：有效
     *
     * @param response
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public Result<String> randomImage(HttpServletResponse response, @PathVariable String key) {
        Result<String> res = new Result<String>();
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseCode + key, "utf-8");
            redisUtil.set(realKey, lowerCaseCode, 60);
            String base64 = RandImageUtil.generate(code);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            res.error500("获取验证码出错" + e.getMessage());
            e.printStackTrace();
        }
        return res;
    }

    /**
     * 后台生成图形数字验证码 ：有效
     *
     * @param response
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomNumberImage/{key}")
    public Result<String> randomNumberImage(HttpServletResponse response, @PathVariable String key) {
        Result<String> res = new Result<String>();
        try {
            String randomNumber = "randomnumber:" + key;
            if (!redisUtil.hasKey(randomNumber)) {
                redisUtil.set(randomNumber, 1, 60);
            } else {
                int number = (int) redisUtil.get(randomNumber);
                number = number + 1;
                if (number >= LOGIN_SMS_BAN_TIME_MAX.intValue()) {
                    res.setSuccess(false);
                    res.error500("请勿频繁获取验证码");
                    return res;
                } else {
                    redisUtil.set(randomNumber, number, 60);
                }
            }

            String code = RandomUtil.randomNumbers(4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseCode + key, "utf-8");
            redisUtil.set(realKey, lowerCaseCode, 60);
            String base64 = RandImageUtil.generate(code);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            res.error500("获取验证码出错" + e.getMessage());
            e.printStackTrace();
        }
        return res;
    }

    /**
     * app登录
     *
     * @param sysLoginModel
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/mLogin", method = RequestMethod.POST)
    public Result<JSONObject> mLogin(@RequestBody SysLoginModel sysLoginModel) throws Exception {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();

        //1. 校验用户是否有效
        SysUser sysUser = sysUserService.getUserByName(username);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("用户名或密码错误");
            return result;
        }

        String orgCode = sysUser.getOrgCode();
        if (oConvertUtils.isEmpty(orgCode)) {
            //如果当前用户无选择部门 查看部门关联信息
            List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
            if (departs == null || departs.size() == 0) {
                result.error500("用户暂未归属部门,不可登录!");
                return result;
            }
            orgCode = departs.get(0).getOrgCode();
            sysUser.setOrgCode(orgCode);
            this.sysUserService.updateUserDepart(username, orgCode);
        }
        JSONObject obj = new JSONObject();
        //用户登录信息
        obj.put("userInfo", sysUser);

        // 生成token
        String token = JwtUtil.sign(username, syspassword);
        // 设置超时时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        //token 信息
        obj.put("token", token);
        result.setResult(obj);
        result.setSuccess(true);
        result.setCode(200);
        baseCommonService.addLog("用户名: " + username + ",登录成功[移动端]！", CommonConstant.LOG_TYPE_1, null);
        return result;
    }

    /**
     * 图形验证码
     *
     * @param sysLoginModel
     * @return
     */
    @RequestMapping(value = "/checkCaptcha", method = RequestMethod.POST)
    public Result<?> checkCaptcha(@RequestBody SysLoginModel sysLoginModel) {
        String captcha = sysLoginModel.getCaptcha();
        String checkKey = sysLoginModel.getCheckKey();
        if (captcha == null) {
            return Result.error("验证码无效");
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + checkKey, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        if (checkCode == null || !checkCode.equals(lowerCaseCaptcha)) {
            return Result.error("验证码错误");
        }
        return Result.ok();
    }
    //重置密码
    @RequestMapping(value = "/resetInvalidTime", method = RequestMethod.GET)
    public Result<?> resetInvalidTime(@RequestParam(name = "username",required = true)String username) {
        SysUser user = sysUserService.getUserByName(username);
        if (user == null) {
            return Result.error("用户不存在");
        }
        if (!UserTypeEnum.管理员.getCode().equals(user.getUType())){
            return Result.error("用户不是管理员");
        }
        /*user.setPassword("Aa.123456");
        String passwordEncode = PasswordUtil.encrypt(user.getUsername(), user.getPassword(), salt);
        user.setPassword(passwordEncode);*/
        Date nowTime = DateUtils.getDate();
        //修改过期时间为三个月之后
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(nowTime);
        calendar.add(Calendar.MONTH, 3);
        Date newOverdueTime = calendar.getTime();
        user.setOverdueTime(newOverdueTime);
        sysUserService.updateById(user);
        return Result.ok();
    }




    public static void main(String[] args) {
        String userpassword = PasswordUtil.encrypt("18132180605", "123456", "Rtklu0iY");
        System.out.println(userpassword);

    }

}
